package com.java.base.exercise.current;

import lombok.SneakyThrows;
import lombok.extern.slf4j.Slf4j;

import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.CopyOnWriteArrayList;
import java.util.concurrent.CopyOnWriteArraySet;
import java.util.concurrent.locks.Condition;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;

/**
 * @Author RenPu
 * @Date 2023/3/13 14:56
 * @Version 1.0
 * @Description: 使用Lock机制实现一个阻塞队列
 **/


public class BlockingQuqueDemo {


    public static void main(String[] args) throws InterruptedException {

        RenPuBlockingQueque renPuBlockingQueque = new RenPuBlockingQueque(10);
        new Thread(){
            @Override
            public void run() {
                    for (int i = 0; i <20 ; i++) {
                        renPuBlockingQueque.put("Mark"+i);
                    }
            }
        }.start();

        CopyOnWriteArrayList<Object> objects = new CopyOnWriteArrayList<>();

        CopyOnWriteArraySet copy=new CopyOnWriteArraySet();



        Thread.sleep(1000L);

        System.out.println("开始获取队列的元素。。TAKE。。。");

        for (int i = 0; i <10 ; i++) {
            renPuBlockingQueque.take();
            Thread.sleep(1000L);
        }
    }



}
@Slf4j
class RenPuBlockingQueque{


    //队列容器
    private List<Object> list=new ArrayList<>();
    //队列的容量
    private int length;
    //锁机制
    private Lock lock=new ReentrantLock();

    public RenPuBlockingQueque(int length) {
        this.length = length;
    }

    Condition putCondition=lock.newCondition();
    Condition takeCondition=lock.newCondition();
    //队列存放元素的方法
    @SneakyThrows
    public void put(Object o) {
        lock.lock();
        try {
                if (list.size() < length) {
                    list.add(o);
                    log.info("队列中放入元素；PUT；；" + o);
                    takeCondition.signal();
                } else {
                    putCondition.await();
                }
            } finally{
                lock.unlock();
            }

        }


    //队列获取元素的方法
   public Object take(){

       try {
           lock.lock();
           if(list.size()>0){
               Object obj= list.remove(0);
               log.info("队列中获取元素；TAKE；；"+obj);
               putCondition.signal();
               return obj;
           }else {
               try {
                   takeCondition.await();
               } catch (Exception e) {
                   e.printStackTrace();
               }
           }
       }finally {
           lock.unlock();
       }
       return null;
   }






}
